package Vshift

import chisel3._
import chisel3.util._
import VShiftInstr._


class Vcon extends Bundle{

  val srcSign = Bool()
  val dstSign = Bool()
  val shiftLr = Bool()

  val sat = Bool()
  val round = Bool()
  val narrow = Bool()
  val long = Bool()
  val insert = Bool()
  val accum = Bool()

}

class Velem extends Bundle {

  val esize = UInt(WIDTH64.W)
  val datasize = UInt(WIDTH128.W)
  val elementNum = UInt(8.W)
  val shiftvaluVcon = UInt(2.W)

}

class Vdec extends Bundle {

  val immh = UInt(4.W)
  val immb = UInt(3.W)
  val size = UInt(2.W)
  val Q    = Bool()

}

class VShiftDecoder extends Module {
  val io = IO(new Bundle() {
    val inst = Input(UInt(WIDTH32.W))

//    val instVld = Input(Bool())
//    val srcData = new SrcData()
//    val dateSome = new DateSome()
    val velem = Output(new Velem())
    val vdec  = Output(new Vdec())
    val vcon = Output(new Vcon())
    val hitNum  = Output(UInt(62.W))
  })

  val ShiftTable: Array[(BitPat, List[UInt])] = Array(
    //                         src_sign
    //                         |    dst_sign
    //                         |    |    shift_left_right
    //                         |    |    |   sat
    //                         |    |    |    |   round
    //                         |    |    |    |    |    narrow
    //                         |    |    |    |    |    |    long
    //                         |    |    |    |    |    |    |    insert
    //                         |    |    |    |    |    |    |    |    accum
    //                         |    |    |    |    |    |    |    |    |     esize(8<<3:0, 8<<size:1, 8<<immh:2)
    //                         |    |    |    |    |    |    |    |    |     |    datasize(64:0, esize:1, Q=?128/64:2)
    //                         |    |    |    |    |    |    |    |    |     |    |    element(1:0, datasize/size:1)
    //                         |    |    |    |    |    |    |    |    |     |    |    |    shift_valu(immh:immb-esize:0, 2*esize - immh:immb:1, SInt([operand2, e, esize]<7:0>):2, esize:3)
    //                         |    |    |    |    |    |    |    |    |     |    |    |    |         sv_flag
  SHL_imm_s        ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  0.U, 0.U, 0.U, 0.U, 1.U ,0.U),
  SHL_imm_v        ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 0.U, 2.U ,1.U),
  SHLL_size_v      ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U, 0.U, 0.U,  1.U, 2.U, 1.U, 3.U, 3.U, 1.U),
  SHRN_imm_v       ->    List(0.U, 0.U, 1.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 4.U, 1.U),
  RSHRN_imm_v      ->    List(0.U, 0.U, 1.U, 0.U, 1.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 5.U, 1.U),
  SLI_imm_s        ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U, 0.U,  0.U, 0.U, 0.U, 0.U, 6.U, 0.U),
  SLI_imm_v        ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U, 0.U,  2.U, 2.U, 1.U, 0.U, 7.U, 1.U),
  SRI_imm_s        ->    List(0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 1.U, 0.U,  0.U, 0.U, 0.U, 1.U, 8.U, 0.U),
  SRI_imm_v        ->    List(0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 1.U, 0.U,  2.U, 2.U, 1.U, 1.U, 9.U, 1.U),
  SSHL_reg_s       ->    List(1.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 0.U, 0.U, 2.U, 10.U, 0.U),
  SSHL_reg_v       ->    List(1.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 11.U, 1.U),
  SSHLL_imm_v      ->    List(1.U, 1.U, 0.U, 0.U, 0.U, 0.U, 1.U, 0.U, 0.U,  2.U, 0.U, 1.U, 0.U, 12.U, 1.U),
  SSHR_imm_s       ->    List(1.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  0.U, 0.U, 0.U, 1.U, 13.U, 0.U),
  SSHR_imm_v       ->    List(1.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 1.U, 14.U, 1.U),
  SQRSHL_reg_s     ->    List(1.U, 1.U, 0.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 1.U, 0.U, 2.U, 15.U, 0.U),
  SQRSHL_reg_v     ->    List(1.U, 1.U, 0.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 16.U, 1.U),
  SQRSHRN_imm_s    ->    List(1.U, 1.U, 1.U, 1.U, 1.U, 1.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 1.U, 17.U, 0.U),
  SQRSHRN_imm_v    ->    List(1.U, 1.U, 1.U, 1.U, 1.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 18.U, 1.U),
  SQRSHRUN_imm_s   ->    List(1.U, 0.U, 1.U, 1.U, 1.U, 1.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 1.U, 19.U, 0.U),
  SQRSHRUN_imm_v   ->    List(1.U, 0.U, 1.U, 1.U, 1.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 20.U, 1.U),
  SQSHL_reg_s      ->    List(1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 1.U, 0.U, 2.U, 21.U, 0.U),
  SQSHL_reg_v      ->    List(1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 22.U, 1.U),
  SQSHL_imm_s      ->    List(1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 0.U, 23.U, 0.U),
  SQSHL_imm_v      ->    List(1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 0.U, 24.U, 1.U),
  SQSHLU_imm_s     ->    List(1.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 0.U, 25.U, 0.U),
  SQSHLU_imm_v     ->    List(1.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 0.U, 26.U, 1.U),
  SQSHRN_imm_s     ->    List(1.U, 1.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 1.U, 27.U, 0.U),
  SQSHRN_imm_v     ->    List(1.U, 1.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 28.U, 1.U),
  SQSHRUN_imm_s    ->    List(1.U, 0.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 1.U, 29.U, 0.U),
  SQSHRUN_imm_v    ->    List(1.U, 0.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 30.U, 1.U),
  SRSHL_reg_s      ->    List(1.U, 1.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 0.U, 0.U, 2.U, 31.U, 0.U),
  SRSHL_reg_v      ->    List(1.U, 1.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 32.U, 1.U),
  SRSHR_imm_s      ->    List(1.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  0.U, 0.U, 0.U, 1.U, 33.U, 0.U),
  SRSHR_imm_v      ->    List(1.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 1.U, 34.U, 1.U),
  SRSRA_imm_s      ->    List(1.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 1.U,  0.U, 0.U, 0.U, 1.U, 35.U, 0.U),
  SRSRA_imm_v      ->    List(1.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 1.U,  2.U, 2.U, 1.U, 1.U, 36.U, 1.U),
  SSRA_imm_s       ->    List(1.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U,  0.U, 0.U, 0.U, 1.U, 37.U, 0.U),
  SSRA_imm_v       ->    List(1.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U,  2.U, 2.U, 1.U, 1.U, 38.U, 1.U),
  UQRSHL_reg_s     ->    List(0.U, 0.U, 0.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 1.U, 0.U, 2.U, 39.U, 0.U),
  UQRSHL_reg_v     ->    List(0.U, 0.U, 0.U, 1.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 40.U, 1.U),
  UQRSHRN_imm_s    ->    List(0.U, 0.U, 1.U, 1.U, 1.U, 1.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 1.U, 41.U, 0.U),
  UQRSHRN_imm_v    ->    List(0.U, 0.U, 1.U, 1.U, 1.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 42.U, 1.U),
  UQSHL_reg_s      ->    List(0.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 1.U, 0.U, 2.U, 43.U, 0.U),
  UQSHL_reg_v      ->    List(0.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 44.U, 1.U),
  UQSHL_imm_s      ->    List(0.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 0.U, 45.U, 0.U),
  UQSHL_imm_v      ->    List(0.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 0.U, 46.U, 1.U),
  UQSHRN_imm_s     ->    List(0.U, 0.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U,  2.U, 1.U, 0.U, 1.U, 47.U, 0.U),
  UQSHRN_imm_v     ->    List(0.U, 0.U, 1.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U,  2.U, 0.U, 1.U, 1.U, 48.U, 1.U),
  URSHL_reg_s      ->    List(0.U, 0.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 0.U, 0.U, 2.U, 49.U, 0.U),
  URSHL_reg_v      ->    List(0.U, 0.U, 0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 50.U, 1.U),
  URSHR_imm_s      ->    List(0.U, 0.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  0.U, 0.U, 0.U, 1.U, 51.U, 0.U),
  URSHR_imm_v      ->    List(0.U, 0.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 1.U, 52.U, 1.U),
  URSRA_imm_s      ->    List(0.U, 0.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 1.U,  0.U, 0.U, 0.U, 1.U, 53.U, 0.U),
  URSRA_imm_v      ->    List(0.U, 0.U, 1.U, 0.U, 1.U, 0.U, 0.U, 0.U, 1.U,  2.U, 2.U, 1.U, 1.U, 54.U, 1.U),
  USHL_reg_s       ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 0.U, 0.U, 2.U, 55.U, 0.U),
  USHL_reg_v       ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  1.U, 2.U, 1.U, 2.U, 56.U, 1.U),
  USHLL_imm_v      ->    List(0.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U, 0.U, 0.U,  2.U, 0.U, 1.U, 2.U, 57.U, 1.U),
  USHR_imm_s       ->    List(0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  0.U, 0.U, 0.U, 1.U, 58.U, 0.U),
  USHR_imm_v       ->    List(0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 0.U,  2.U, 2.U, 1.U, 1.U, 59.U, 1.U),
  USRA_imm_s       ->    List(0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U,  0.U, 0.U, 0.U, 1.U, 60.U, 0.U),
  USRA_imm_v       ->    List(0.U, 0.U, 1.U, 0.U, 0.U, 0.U, 0.U, 0.U, 1.U,  2.U, 2.U, 1.U, 1.U, 61.U, 1.U)

  )

  val srcSign = Wire(Bool())
  val dstSign = Wire(Bool())
  val shiftLr = Wire(Bool())

  val sat = Wire(Bool())
  val round = Wire(Bool())
  val narrow = Wire(Bool())
  val long = Wire(Bool())
  val insert = Wire(Bool())
  val accum = Wire(Bool())

  val VconEsize = Wire(UInt(2.W))
  val VconDatasize = Wire(UInt(2.W))
  val VconElements = Wire(UInt(2.W))
  val VconShiftvalu = Wire(UInt(2.W))
  val HitNum      = Wire(UInt(62.W))
  val svFlag      = Wire(UInt(1.W))

  io.hitNum := HitNum
  srcSign := false.B
  dstSign := false.B
  shiftLr := false.B

  sat := false.B
  round := false.B
  narrow := false.B
  long := false.B
  insert := false.B
  accum := false.B

  VconEsize := 0.U
  VconDatasize := 0.U
  VconElements := 0.U
  VconShiftvalu := 0.U
  HitNum := 0.U
  svFlag := 0.U

  for (i <- 0 to 60){
    when(ShiftTable(i)._1 === io.inst){
      val seq = ShiftTable(i)._2
      srcSign := seq(0)
      dstSign := seq(1)
      shiftLr := seq(2)

      sat := seq(3)
      round := seq(4)
      narrow := seq(5)
      long := seq(6)
      insert := seq(7)
      accum := seq(8)

      VconEsize := seq(9)
      VconDatasize := seq(10)
      VconElements := seq(11)
      VconShiftvalu := seq(12)
      HitNum := seq(13)
      svFlag := seq(14)


    }
  }

  //Wire sigin

  val esize = Wire(UInt(WIDTH64.W))
  val datasize = Wire(UInt(WIDTH64.W))
  val elementNum = Wire(UInt(8.W))

  //inst decoder

  val immh = Wire(UInt(4.W))
  val immb = Wire(UInt(3.W))
  val size = Wire(UInt(2.W))
  val Q    = Wire(Bool())

  when(svFlag === 0.U){
    Q := 0.U
  }.otherwise{
    Q := io.inst(30)
  }

  immh := io.inst(22,19)
  immb := io.inst(18,16)
  size := io.inst(23,22)

  io.vdec.Q := Q
  io.vdec.immh := immh
  io.vdec.immb := immb
  io.vdec.size := size



  //----------------------------------------------------------------------
  //esize generate


  when(VconEsize === 0.U) {
    esize := 64.U
  }.elsewhen(VconEsize === 1.U) {
    esize := 8.U << size
  }.elsewhen(VconEsize === 2.U) {
    esize := 8.U << SetBit4(immh)
  }.otherwise {
    esize := 0.U
  }

  //----------------------------------------------------------------------
  //datasize generate

  when(VconDatasize === 0.U) {
    datasize := 64.U
  }.elsewhen(VconDatasize === 1.U) {
    datasize := esize
  }.elsewhen(VconDatasize === 2.U) {
    datasize := 64.U  //Mux(Q === 0.U, 64.U, 128.U)
  }.otherwise {
    datasize := 0.U
  }



  //----------------------------------------------------------------------
  //elementNum generate
  //     when elementNum == 1 => 64、32、16、8
  //     when elementNum == 2 => 32
  //     when elementNum == 4 => 16
  //     when elementNum == 8 => 8

  when(VconElements === 0.U) {
    elementNum := 1.U
  }.elsewhen(VconElements === 1.U) {
    elementNum := datasize/esize
  }.otherwise {
    elementNum := 0.U
  }


  //----------------------------------------------------------------------
  //shiftvaluVon generate

  io.vcon.srcSign := srcSign
  io.vcon.dstSign := dstSign
  io.vcon.shiftLr := shiftLr

  io.vcon.sat := sat
  io.vcon.round := round
  io.vcon.narrow := narrow
  io.vcon.long := long
  io.vcon.insert := insert
  io.vcon.accum := accum

  io.velem.esize := esize
  io.velem.datasize := datasize
  io.velem.elementNum := elementNum
  io.velem.shiftvaluVcon := VconShiftvalu




}